package com.mini.framework.core;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.LinkedHashSet;
import java.util.Properties;
import java.util.Set;

import com.mini.framework.core.annotation.Component;
import com.mini.framework.core.annotation.Controller;

public class AnnotationBeanReader extends ApplicationBeanReader {
	
	private static final String DEFAULT_CONF_FILE = "/conf.properties";
	
	private static final String COMPONENT_SCAN = "component.scan";
	
	private Properties properties = new Properties();
	
	private Set<Class<?>> classSet = new LinkedHashSet<Class<?>>();
	
	@Override
	public Set<Class<?>> getClasses(String path) {
		String propertiesPath = DEFAULT_CONF_FILE;
		if(path != null){
			propertiesPath = path;
		}
		try{
			properties.load(AnnotationBeanReader.class.getResourceAsStream(propertiesPath));
			String scanPath = properties.getProperty(COMPONENT_SCAN);
			scanPath(scanPath);
		}catch(Exception e){
			e.printStackTrace();
		}
		return classSet;
	}

	@Override
	public Properties getProperties() {
		return properties;
	}
	
	private void scanPath(String path) throws Exception{
		String packDir = path.replace('.', '/');
		Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packDir);
		while(urls.hasMoreElements()){
			URL url = urls.nextElement();
			String filePath = URLDecoder.decode(url.getFile(),"UTF-8");
			addClassByFile(path,filePath);
		}
	}
	
	private void addClassByFile(String path,String filePath) throws Exception{
		File file = new File(filePath);
		File[] files = file.listFiles();
		for(File f : files){
			if(f.isDirectory()){
				addClassByFile(path+"."+f.getName(),f.getAbsolutePath());
			}else{
				String className = f.getName().substring(0,f.getName().length()-6);
				Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass(path+"."+className);
				if(isAnnotationPresent(clazz)){
					classSet.add(clazz);
				}
			}
		}
	}
	
	private boolean isAnnotationPresent(Class<?> c){
		return c.isAnnotationPresent(Controller.class)||c.isAnnotationPresent(Component.class);
	}

}
